/*
*	Copyright(c) 2020 lutianming email：641471957@qq.com
*
*	Sheeps may be copied only under the terms of the GNU Affero General Public License v3.0
*/

#include "sheeps.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "framework.h"
#include "SheepsMain.h"
#include "lsheepsrun.h"
#include "BridgeProtocol.h"
#include "lserverhook.h"

#ifdef __WINDOWS__
#include "conio.h"
#ifdef _DEBUG
#ifndef _WIN64
#pragma comment(lib,"..\\Win32\\sheeps\\Debug\\lsheeps.lib")
#pragma comment(lib,"..\\Win32\\sheeps\\Debug\\lserverhook.lib")

#else
#pragma comment(lib, "..\\X64\\sheeps\\Debug\\lsheeps.lib")
#pragma comment(lib, "..\\X64\\sheeps\\Debug\\lserverhook.lib")

#endif // _WIN32
#else
#ifndef _WIN64
#pragma comment(lib, "..\\Win32\\sheeps\\Release\\lsheeps.lib")
#pragma comment(lib, "..\\Win32\\sheeps\\Release\\lserverhook.lib")

#else
#pragma comment(lib, "..\\X64\\sheeps\\Release\\lsheeps.lib")
#pragma comment(lib, "..\\X64\\sheeps\\Release\\lserverhook.lib")

#endif // _WIN32
#endif
#define strcasecmp _stricmp
#else
#include<sys/file.h>

int lock_fd = 0;
#endif // __WINDOWS__

enum {
	MODE_CS = 0,
	MODE_S,
	MODE_C,
	MODE_TEST
};

enum {
	Script_Lua = 0,
	Script_Bridge
};

bool			script_test = false;

int				mode = MODE_CS;
const char*		argv_ip = NULL;
int				argv_port = 0;
bool			argv_local_server = true;
int				argv_projectid = -1;
const char*		argv_groupid = NULL;
const char*		argv_config_file = NULL;
int				language = Script_Lua;

/*lua or javascript or python parm*/
const char*		argv_main_script = NULL;

const char* parms_des =  "\n参数说明：-m [] -ip [] -port [] -l [] -s [] -c [] -p [] -g []\n\n\
-m:	启动模式,c-负载端模式,s-控制端模式,cs-单机模式\n\
-ip:	指定控制端ip地址,否则从配置文件读取\n\
-port:	指定控制端端口，否则从配置文件读取\n\
-l:	指定负载端使用脚本语言,lua、python,默认lua\n\
-s:	指定负载端脚本文件\n\
-c:	指定负载端ini配置文件\n\
-p:	指定负载端项目id，默认0\n\
-g:	指定负载端组id，默认0\n\
-console:	linux下显示控制台信息\n\
单机示例：	supersheeps.exe -m cs\n\
控制端示例：	supersheeps.exe -m s -port 1080\n\
负载端示例：	supersheeps.exe -m c -p 0\n";

static int show_parms()
{
	printf(parms_des);
	return 0;
}

bool sheeps_aready_run() {
#ifdef NDEBUG
#ifdef __WINDOWS__
	HANDLE mutex = CreateMutexA(NULL, false, "mutex_for_sheeps");
	if (mutex && ERROR_ALREADY_EXISTS == GetLastError()) {
		printf("SuperSheeps正在运行，请勿重复启动\n");
		system("pause");
		return true;
	}
	return false;
#else
	lock_fd = open("/tmp/supersheeps_stat", O_RDONLY|O_CREAT, 0644);
    if (lock_fd < 0) {
        return false;
    }
	int ret = flock(lock_fd, LOCK_EX | LOCK_NB);
    if ( ret < 0) {
		printf("SuperSheeps正在运行，请勿重复启动\n");
        return true;
    }
    return false;
#endif
#else
	return false;
#endif
}

static int run_mode_s(){
	if (argv_port <= 0) argv_port = config_get_int_value("common", "srv_port", 1080);
	argv_ip = argv_ip ? argv_ip : "::";
	return SheepsRunServerManager(argv_ip, argv_port);
}

static int run_mode_t()
{
	if (language == Script_Lua)
		SheepsLuaTest(argv_main_script);
	//else if (language == Script_Js)
	//	SheepsJsTest(main_script);
#ifdef PYTHON_SUPPORT
	else if (language == Script_Python)
		SheepsPythonTest();
#endif
	return 0;
}

static int run_mode_c()
{
	if (language == Script_Lua)
		TaskManagerRunWithLua(argv_projectid, argv_groupid, argv_local_server, argv_ip, argv_port, argv_config_file, argv_main_script);
	else if (language == Script_Bridge)
		TaskManagerRunWithBridge(argv_projectid, argv_groupid, argv_local_server, argv_config_file);
	else {
		printf("不支持的启动参数！！！");
	}
	return 0;
}

static int check_other_parms(char* parm)
{
	return show_parms();
}

static int check_input_params(int argc, char* argv[]) {
	for (int i = 1; i < argc; i++)
	{
		if ( (!strcmp("-m", argv[i]) || !strcmp("m", argv[i])) && i + 1 < argc)
		{
			if (!strcmp("s", argv[i + 1]))
			{
				argv_local_server = true;
				mode = MODE_S;
			}
			else if (!strcmp("c", argv[i + 1]))
			{
				argv_local_server = false;
				mode = MODE_C;
			}
			else if (!strcmp("cs", argv[i + 1]) || !strcmp("sc", argv[i + 1]))
			{
				argv_local_server = true;
				mode = MODE_CS;
			}
			else if (!strcmp("t", argv[i + 1]))
			{
				mode = MODE_TEST;
			}
			i++;
		}
		else if ((!strcmp("-ip", argv[i]) || !strcmp("ip", argv[i])) && i + 1 < argc)
		{
			argv_ip = argv[i + 1];
			i++;
		}
		else if ((!strcmp("-port", argv[i])|| !strcmp("port", argv[i])) && i + 1 < argc)
		{
			argv_port = atoi(argv[i + 1]);
			i++;
		}
		else if ((!strcmp("-l", argv[i])|| !strcmp("l", argv[i])) && i + 1 < argc)
		{
			if (!strcmp("lua", argv[i + 1]))
				language = Script_Lua;
			else if (!strcmp("bridge", argv[i + 1]))
				language = Script_Bridge;
		}
		else if ((!strcmp("-s", argv[i])|| !strcmp("s", argv[i])) && i + 1 < argc)
		{
			argv_main_script = argv[i + 1];
			i++;
		}
		else if ((!strcmp("-c", argv[i])|| !strcmp("c", argv[i])) && i + 1 < argc)
		{
			argv_config_file = argv[i + 1];
			i++;
		}
		else if ((!strcmp("-p", argv[i])|| !strcmp("p", argv[i])) && i + 1 < argc)
		{
			argv_projectid = atoi(argv[i + 1]);
			i++;
		}
		else if ((!strcmp("-g", argv[i])|| !strcmp("g", argv[i])) && i + 1 < argc)
		{
			argv_groupid = argv[i + 1];
			i++;
		}
		else if (!strcmp("-console", argv[i]) || !strcmp("console", argv[i]))
		{
			ShowConsole = true;
		}
	}

	if (argv_projectid < 0) {
		argv_projectid = config_get_int_value("agent", "project_id", 0);
	}

	if (mode == MODE_TEST)
	{
		return run_mode_t();
	}

	if (sheeps_aready_run()) return 0;  //后续功能无法支持程序重复启动
	if (argv_local_server == true)
	{
		server_hook_set();
	}
	if (mode == MODE_S)
		return run_mode_s();
	return run_mode_c();
}

#ifdef __WINDOWS__
#define clear_screen "CLS"
#else
#include <termios.h>
#define clear_screen "clear"
struct termios oldt, newt;
static void changemode(int dir) {
	if (dir == 1) {
		tcgetattr(STDIN_FILENO, &oldt);
		newt = oldt;
		newt.c_lflag &= ~(ICANON | ECHO);
		tcsetattr(STDIN_FILENO, TCSANOW, &newt);
	}
	else {
		oldt.c_lflag |= ICANON | ECHOE;
		oldt.c_lflag &= ~ECHOPRT;
		oldt.c_cc[VERASE] = 0x8;
		tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
	}
}

static int _kbhit(void) {
	struct timeval tv;
	fd_set rdfs;
	tv.tv_sec = 0;
	tv.tv_usec = 0;
	FD_ZERO(&rdfs);
	FD_SET(STDIN_FILENO, &rdfs);
	select(STDIN_FILENO + 1, &rdfs, NULL, NULL, &tv);
	return FD_ISSET(STDIN_FILENO, &rdfs);
}
#endif

static int input_params(char* runfile) {
	char buf[1024] = { 0x0 };
	char* argv[32] = { 0x0 };
	argv[0] = runfile;
	int i = 1;
	bool flag = false;
	int second = 5;
#ifndef __WINDOWS__
	changemode(1);
#endif
	while (true){
		system(clear_screen);
		printf("正在以默认参数启动...\n按任意键指定启动参数(%d)\n", second);
		TimeSleep(1000);
		if (_kbhit()) {
#ifdef __WINDOWS__
			_getch();
#else
			getchar();
#endif
			flag = true;
			break;
		}
		if (second == 0) break;
		second--;
	}
#ifndef __WINDOWS__
	changemode(0);
#endif
	system(clear_screen);
	if (flag) {
		printf("%s\n\n请输入参数：", parms_des);
		fgets(buf, sizeof(buf), stdin);
		char* p = buf;
		while (*p != '\n' && *p != 0x0) {
			if (*p == ' ') {
				flag = true;
				*p = 0x0;
			}
			else if (*p != ' ' && flag == true) {
				argv[i] = p;
				flag = false;
				i++;
			}
			p++;
		}
		*p = 0x0;
	}
	return check_input_params(i, argv);
}

int __STDCALL run_with_parms(int argc, char* argv[])
{
#ifdef __WINDOWS__
	system("chcp 65001");
#endif
#define NOT_PRAM(x) strcmp(argv[1], x)
	if (argc == 1) {
		return input_params(argv[0]);
	}
	else if (argc == 2 && (NOT_PRAM("-framework")) && (NOT_PRAM("-console")) && (NOT_PRAM("console")))
		return check_other_parms(argv[1]);
	return check_input_params(argc, argv);
}
